using System.Collections.Generic;
using System.Diagnostics;

namespace GeoAzure.Core
{
    public class InsertionContext<T>
        where T : class
    {
        private readonly IndexEntry<T> _entry;
        private readonly int _targetLevel;
        private IList<int> _overflownLevels;
        private readonly RTree<T> _targetIndex;

        internal InsertionContext(IndexEntry<T> newEntry, int targetLevel, RTree<T> targetIndex)
        {
            if (targetLevel == 0)
                Debug.Assert(newEntry.Element != null, "Insertions targetting the leaf level should be for an element.");
            else
            {
                Debug.Assert(newEntry.Node != null, "Insertions targetting a non-leaf level should be for a TreeNode.");
            }
            _entry = newEntry;
            _targetLevel = targetLevel;
            _targetIndex = targetIndex;
        }

        // this constructor is called during split or reinsertion
        // we will share the overflown levels with the previous context,
        // if any, to detect overflows occuring many times at same level
        // for insertion of a single initial element in the index
        internal InsertionContext(IndexEntry<T> newEntry, int targetLevel, InsertionContext<T> previousContext)
        {
            if (targetLevel == 0)
                Debug.Assert(newEntry.Element != null, "Insertions targetting the leaf level should be for an element.");
            else
            {
                Debug.Assert(newEntry.Node != null, "Insertions targetting a non-leaf level should be for a TreeNode.");
            }
            _entry = newEntry;
            _targetLevel = targetLevel;
            if (previousContext != null)
            {
                _overflownLevels = previousContext._overflownLevels;
                _targetIndex = previousContext.TargetIndex;
            }
        }

        public int TargetLevel
        {
            get { return _targetLevel; }
        }

        internal IndexEntry<T> Entry
        {
            get { return _entry; }
        }

        internal RTree<T> TargetIndex
        {
            get
            {
                return _targetIndex;
            }
        }

        public bool HasLevelOverflownPreviously(int level)
        {
            if (_overflownLevels == null)
                return false;
            return _overflownLevels.Contains(level);
        }

        public void AddOverflownLevel(int level)
        {
            if (_overflownLevels == null)
                _overflownLevels = new List<int>(3);
            _overflownLevels.Add(level);
        }
    }
}